//
// Created by ZMX on 2017/10/23.
//

#include "GroupLayer.h"

GroupLayer::GroupLayer(int l, int t, int r, int b) : left(l), top(t), right(r), bottom(b) {
    laySet.clear();
}

void GroupLayer::draw() {
    cleanShape();
    showShape();
    Print(laySet, false);
}

void GroupLayer::addShape(Shape_Base *base) {
    shapePosition.first = (int) MAPW / 2;
    shapePosition.second = 0;
    delete moveShape;

    moveShape = base;
    showShape();
}

STATUS GroupLayer::move(int direct) {
    pair<int, int> newPosition;
    newPosition.first = shapePosition.first;
    newPosition.second = shapePosition.second;

    switch (direct) {
        case KEY_UP: {
            newPosition.second--;
            break;
        }
        case KEY_DOWN: {
            newPosition.second++;
            break;
        }
        case KEY_LEFT: {
            newPosition.first--;
            break;
        }
        case KEY_RIGHT: {
            newPosition.first++;
            break;
        }
        default:
            return STATUS::MOVE;
    }
    static set<Node> newSet;
    cal_shape_position(newPosition, newSet);

    bool touched = hasTouched(newSet);
    bool in_bottom = (newPosition.second == bottom - moveShape->getHeight());

    if (touched) {
        if (direct == KEY_DOWN) {
            cleanShape();
            auto it = shapeSet.begin();
            while (it != shapeSet.end()) {
                laySet.insert(Node(it->coord.first, it->coord.second, 6));
                it++;
            }

            Print(laySet, false);
            return STATUS::BOTTOM;
        } else {
            return STATUS::MOVE;
        }
    } else if (in_bottom) {
        cleanShape();

        shapeSet.clear();

        auto it = newSet.begin();
        while (it != newSet.end()) {
            laySet.insert(Node(it->coord.first, it->coord.second, 6));
            it++;
        }

        Print(laySet, false);
        return STATUS::BOTTOM;
    } else {
        cleanShape();

        shapePosition.first = newPosition.first;
        shapePosition.second = newPosition.second;
        shapeSet = newSet;

        if (!shapeSet.empty())
            Print(shapeSet, false);

        Print(laySet, false);
    }
    return STATUS::MOVE;
}

void GroupLayer::cal_shape_position(pair<int, int> &p, set<Node> &ns) {
    set<pair<int, int >> set;
    moveShape->getPosition(set);
    ns.clear();
    auto it = set.begin();

    int shape_width = moveShape->getWidth();
    int shape_height = moveShape->getHeight();

    if (p.first <= left) {
        p.first = left;
    }

    if (p.first + shape_width >= right) {
        p.first = right - shape_width;
    }

    if (p.second <= top) {
        p.second = top;
    }
    if (p.second + shape_height >= bottom) {
        p.second = bottom - shape_height;
    }

    int l = p.first;
    int t = p.second;

    while (it != set.end()) {
        int x = it->first + l;
        int y = it->second + t;
        ns.insert(Node(x, y, 6));
        it++;
    }
}

void GroupLayer::cleanShape() {
    set<pair<int, int >> set1;
    moveShape->getPosition(set1);
    set<Node> ps;
    auto it = set1.begin();

    int l = shapePosition.first;
    int t = shapePosition.second;

    while (it != set1.end()) {
        ps.insert(Node(it->first + l, it->second + t, 6));
        it++;
    }
    if (!ps.empty())
        Print(ps, true);
}

void GroupLayer::switch90() {
    cleanShape();
    moveShape->switch90();
    showShape();
    Print(laySet, false);
}

bool GroupLayer::hasTouched(set<Node> &set) {
    if (set.empty() || laySet.empty())
        return false;

    auto shapeItl = set.begin();
    while (shapeItl != set.end()) {
        auto shape = shapeItl->coord;

        auto layItl = laySet.begin();
        while (layItl != laySet.end()) {
            auto layNode = layItl->coord;
            if ((shape.first == layNode.first) && (shape.second == layNode.second)) {
                return true;
            }

            layItl++;
        }
        shapeItl++;
    }

    return false;
}

void GroupLayer::showShape() {
    cal_shape_position(shapePosition, shapeSet);
    if (!shapeSet.empty())
        Print(shapeSet, false);
}
